﻿using pdfer.FileObjects;
using pdfer.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using SysEncoding = System.Text.Encoding;

namespace pdfer.PdfObjecs.Fonts
{
    /// <summary>
    /// 通用操作
    /// 1. 如第 5.5.5 节 “字符编码”中所述，在字体的 Encoding 项中查找字符代码，以获取字符名称。
    /// 2. 在字体的 CharProcs 字典中查找字符名称，以获取包含字形描述的流对象。（如果名称未作为键出现在 CharProcs 中，则不会绘制字形。
    /// 3. 调用字形描述，如下所述。图形状态在此调用之前保存，并在此调用之后恢复;因此，字形描述对图形状态所做的任何更改在完成后都不会保留。
    /// 
    /// 
    /// </summary>
    internal class FontType3Dictionary : PdfFileObject, IFontTypeDictionary
    {
        public FontType3Dictionary(PdfFileObject pdfFileObject)
            : base(pdfFileObject)
        {
            if (pdfFileObject.TryGetValue(PdfName.Key_Type, out object? val))
            {
                Type = PdfParserUtils.ParseString(val);
                if (Type != PdfTypeConst.Type_Font)
                {
                    throw new Exception("类型必须是 /Font");
                }
            }
            if (pdfFileObject.TryGetValue(PdfName.Key_Subtype, out val))
            {
                Subtype = PdfParserUtils.ParseString(val);
                if (Subtype != PdfTypeConst.Type_Font_Type3)
                {
                    throw new Exception("类型必须是 /Type3");
                }
            }
        }
        public string Type { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Subtype { get; set; }

        [Obsolete("All Acrobat viewers ignore the Name entry in a font dictionary. ")]
        public string Name
        {
            get
            {
                return GetDicStringVal(PdfName.Key_Name);
            }
        }

        private Vector4? _FontBBox;

        /// <summary>
        /// 矩形
        /// </summary>
        public Vector4 FontBBox
        {
            get
            {
                if (_FontBBox == null)
                {
                    var _tmp = GetDicListVal(PdfName.Key_FontBBox, PdfParserUtils.Trans2Single);
                    _FontBBox = new Vector4(_tmp.ToArray());
                }
                return _FontBBox ?? default;
            }
        }

        private Vector<float>? _FontMatrix;

        /// <summary>
        /// 6 个元素
        /// </summary>
        public Vector<float> FontMatrix
        {
            get
            {
                if (_FontMatrix == null)
                {
                    var _tmp = GetDicListVal(PdfName.Key_FontMatrix, PdfParserUtils.Trans2Single);
                    if (_tmp == null)
                    {
                        _tmp = [0, 0, 0, 0, 0, 0];
                    }
                    while (_tmp.Count < 6)
                    {
                        _tmp.Add(0);
                    }
                    _FontMatrix = new Vector<float>(_tmp[0..6].ToArray());
                }
                return _FontMatrix ?? default;
            }
        }

        /// <summary>
        /// （必填）一个字典，其中每个键都是一个字符名称，与该键关联的值是一个内容流，用于构造和绘制该字符的字形。
        /// 流的第一个运算符必须包括 d0 或 d1，后跟描述一个或多个图形对象的运算符，这些对象可能包括路径、文本或图像对象。
        /// 有关 Type 3 字形描述的更多详细信息，请参阅下文。
        /// </summary>
        public Dictionary<string, object> CharProcs
        {
            get
            {
                return GetDicDictionaryVal(PdfName.Key_CharProcs);
            }
        }

        /// <summary>
        /// （必填）一个编码字典，其 Differences 数组指定了此字体的完整字符编码（参见第 5.5.5 节 “字符编码”;
        /// 另请参阅附录 H 中的实现说明 64）。
        /// </summary>
        public object Encoding
        {
            get
            {
                if (TryGetValue(PdfName.Key_Encoding, out var _val))
                {
                    if (_val is System.Collections.IDictionary)
                    {
                        return ParseDictionary(PdfName.Key_Encoding);
                    }
                    else
                    {
                        return ParseString(PdfName.Key_Encoding);
                    }
                }
                return null;
            }
        }

        /// <summary>
        /// （必填）字体的 Widths 数组中定义的第一个字符代码。
        /// </para>
        /// </summary>
        public int FirstChar
        {
            get
            {
                return GetDicInt32Val(PdfName.Key_FirstChar);
            }
        }

        /// <summary>
        /// （必填）字体的 Widths 数组中定义的最后一个字符代码。
        /// </summary>
        public int LastChar
        {
            get
            {
                return GetDicInt32Val(PdfName.Key_LastChar);
            }
        }

        /// <summary>
        /// （必需;最好是间接引用）一个 （LastChar − FirstChar 1） 宽度数组，每个元素是等于 FirstChar 加上数组索引的字符代码的字形宽度。
        /// <para>
        /// 对于 FirstChar 到 LastChar 范围之外的字符代码，宽度为 0。
        /// </para>
        /// 这些宽度在 FontMatrix 指定的字形空间中进行解释 （与 Type 1 字体的宽度不同，后者以文本空间） 单位的千分之一为单位。
        /// <para></para>
        /// 注： 如果 FontMatrix 指定旋转，则仅使用转换宽度的水平分量。也就是说，生成的位移在文本空间中始终是水平的，就像所有简单字体一样。
        /// </summary>
        public List<int> Widths
        {
            get
            {
                return GetDicListVal(PdfName.Key_Widths, PdfParserUtils.Trans2Int32);
            }
        }

        /// <summary>
        /// （在加标签的 PDF 文档中是必需的;必须是间接引用）描述字体的默认度量（而不是其字形宽度）的字体描述符（参见第 5.7 节 “字体描述符”）。
        /// </summary>
        public FontDescriptorDictionary FontDescriptor
        {
            get
            {
                var id = GetDicStringVal(PdfName.Key_ToUnicode);
                if (id == null || id[^1] != 'R')
                {
                    return null;
                }
                var obj = GetIndirectObj(id);
                return new FontDescriptorDictionary(obj);
            }
        }

        /// <summary>
        /// （可选，但强烈建议;PDF 1.2） 此字体的字形描述所需的命名资源列表，例如字体和图像（请参阅第 3.7.2 节 “资源词典”）。
        /// 如果任何字形描述引用命名资源，但此词典不存在，则会在使用该字体的页面的资源词典中查找名称。（见附录 H 中的实施说明 65。
        /// </summary>
        public Dictionary<string, object>? Resources
        {
            get
            {
                return GetDicDictionaryVal(PdfName.Key_Resources);
            }
        }

        /// <summary>
        /// （可选;PDF 1.2） 包含将字符代码映射到 Unicode 值的 CMap 文件的流（请参阅第 5.9 节 “提取文本内容”）。
        /// </summary>
        public PdfFileObject? ToUnicode
        {
            get
            {
                var obj = GetDicPdfFileObjVal(PdfName.Key_ToUnicode);
                return obj;
            }
        }

        public string GetString(ReadOnlySpan<Byte> data)
        {
            if (ToUnicode == null)
            {
                if (Encoding == "/WinAnsiEncoding")
                {
                    return SysEncoding.ASCII.GetString(data);
                }
                else
                {
                    return SysEncoding.ASCII.GetString(data);
                }
            }
            else
            {
                var cmapEngine = new CMapCompilationEngine();
                cmapEngine.ParseToCMapObject(ToUnicode.DecodeStreamData);
                var cmap = cmapEngine.CMapObj;

                return cmap.GetString(data);
            }
        }
    }
}
